package cn.tedu.epidemic.webapi.service.impl;

import cn.tedu.community.commons.excepion.ServiceException;
import cn.tedu.community.commons.pojo.user.dto.*;
import cn.tedu.community.commons.pojo.user.entity.*;
import cn.tedu.community.commons.pojo.user.vo.UserCurrentVO;
import cn.tedu.community.commons.pojo.user.vo.UserListVO;
import cn.tedu.community.commons.restful.JsonPage;
import cn.tedu.community.commons.restful.ServiceCode;
import cn.tedu.epidemic.service.PhotoUploadService;
import cn.tedu.epidemic.service.UserService;
import cn.tedu.epidemic.webapi.mapper.HealthMapper;
import cn.tedu.epidemic.webapi.mapper.ReturnHomeMapper;
import cn.tedu.epidemic.webapi.mapper.UserMapper;
import cn.tedu.epidemic.webapi.security.CurrentUser;
import cn.tedu.epidemic.webapi.security.UserDuct;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.assertj.core.util.DateUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户Service实现类
 */
@Slf4j
@Service
@DubboService
public class UserServiceImpl implements UserService {
    @Value("${community.jwt.secret-Key}")
    private String secretKey;
    @Value("${community.jwt.duration-in-minute}")
    private Long durationInMinute;
    @Autowired
    private UserMapper mapper;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private PhotoUploadService uploadService;
    @Autowired
    private ReturnHomeMapper returnHomeMapper;
    @Autowired
    private HealthMapper healthMapper;

    /**
     * 用户注册
     */
    @Override
    public void reg(UserRegDTO regDTO) {
        if (!regDTO.getUserPassword().equals(regDTO.getConfirmPassword())) {
            throw new ServiceException(ServiceCode.ERR_PASSWORD,
                    "两次输入的密码不一致,请重新输入！");
        }
        UserInfo user = new UserInfo();
        if (mapper.countByNameOrPhone(regDTO.getUserName(), regDTO.getUserPhone()) > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "用户名或手机号已被注册过,请返回登录!");
        }
        BeanUtils.copyProperties(regDTO, user);
        user.setPhoto("1689402472524.jpeg");
        user.setUserPassword(passwordEncoder.encode(user.getUserPassword()));
        int insertRows = mapper.userReg(user);
        if (insertRows != 1) {
            String message = "注册用户失败，服务器忙，请稍后再次尝试！";
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }
    }

    /**
     * 查询当前用户信息
     */
    @Override
    public UserCurrentVO currentUser() {
        Long userId = CurrentUser.getUserId();
        String returnHomeTime = returnHomeMapper.returnHomeTime(userId);
        if (returnHomeTime != null) {
            Date result = DateUtil.parse(returnHomeTime);
            long millisTime = result.getTime();
            long currentTime = System.currentTimeMillis();
            if (currentTime - millisTime > 1209600000) {
                UserInfo user = new UserInfo();
                user.setId(userId);
                user.setIsReturnPeople(0);
                int update = mapper.update(user);
                if (update!=1){
                    throw new ServiceException(ServiceCode.ERR_UPDATE,"服务器繁忙，请稍后重试！");
                }
                log.debug("查询到该用户最近一次返乡时间已超过14天，已将该用户设为非返乡用户！");
            }
        }
        return mapper.selectCurrentById(userId);
    }

    /**
     * 用户登录
     */
    @Override
    public String login(UserLoginDTO loginDTO) {
        log.debug("开始处理【用户登录】的业务，参数：{}", loginDTO);
        // 执行认证
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                loginDTO.getUserName(), loginDTO.getUserPassword());
        //以下调用方法时需要获取返回值
        Authentication authenticationResult
                = authenticationManager.authenticate(authentication);
        log.debug("认证信息：{}", authenticationResult);
        //将通过认证的用户的相关信息存入到jwt中
        //准备生成jwt的相关数据
        Date date = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);
        UserDuct principal = (UserDuct) authenticationResult.getPrincipal();
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", principal.getId());
        claims.put("username", principal.getUsername());
        //生成jwt
        String jwt = Jwts.builder()
                //Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                //Payload
                .setClaims(claims)
                //Signature
                .setExpiration(date)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        return jwt;
    }

    @Override
    public void update(UserUpdateDTO userUpdateDTO) {
        Long userId = CurrentUser.getUserId();
        if (mapper.countByNameAndNotId(userUpdateDTO.getUserName(), userId) > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "用户名已被占用，请重新输入！");
        }
        if (mapper.countByEmailAndNotId(userUpdateDTO.getEmail(), userId) > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "电子邮箱已被占用，请重新输入！");
        }
        if (mapper.countByIdentityAndNotId(userUpdateDTO.getIdentity(), userId) > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "身份证号已被占用，请重新输入！");
        }
        if (mapper.countByPhoneAndNotId(userUpdateDTO.getUserPhone(), userId) > 0) {
            throw new ServiceException(ServiceCode.ERR_CONFLICT, "手机号已被占用，请重新输入！");
        }
        UserCurrentVO userCurrentVO = mapper.selectCurrentById(userId);
        if (!userUpdateDTO.getPhoto().equals(userCurrentVO.getPhoto())) {
            uploadService.deletePhoto(userCurrentVO.getPhoto());
        }

        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(userUpdateDTO, userInfo);
        userInfo.setId(userId);
        int count = mapper.update(userInfo);
        if (count != 1) {
            String message = "修改用户信息失败，请稍后再次尝试！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public void updatePassById(UserUpdatePassDTO updatePassDTO) {
        Long userId = CurrentUser.getUserId();
        String encodePass = mapper.encodePass(userId);
        if (!passwordEncoder.matches(updatePassDTO.getOldPassword(), encodePass)) {
            String message = "原始密码不正确，请重新输入！";
            throw new ServiceException(ServiceCode.ERR_SELECT, message);
        }
        if (!updatePassDTO.getNewPassword().equals(updatePassDTO.getConfirmPassword())) {
            String message = "两次新密码输入不一致，请重新输入！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        updatePassDTO.setNewPassword(passwordEncoder.encode(updatePassDTO.getNewPassword()));
        int updatePass = mapper.updatePassById(userId, updatePassDTO.getNewPassword());
        if (updatePass != 1) {
            String message = "服务器繁忙，请稍后再试！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        SecurityContextHolder.clearContext();
    }

    @Override
    public void countByPhone(String userPhone) {
        if (mapper.countByNameOrPhone("写死", userPhone) == 0) {
            String message = "手机号错误或不存在，请重新输入！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }
    }

    @Override
    public void updatePassByPhone(UserForGotPassDTO forGotPassDTO) {
        if (mapper.countByNameOrPhone("写死", forGotPassDTO.getUserPhone()) == 0) {
            String message = "手机号错误或不存在，请重新输入！";
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, message);
        }

        if (!forGotPassDTO.getUserPassword().equals(forGotPassDTO.getConfirmPassword())) {
            String message = "两次输入的密码不一致，请重新输入！";
            throw new ServiceException(ServiceCode.ERR_PASSWORD, message);
        }

        forGotPassDTO.setUserPassword(passwordEncoder.encode(forGotPassDTO.getUserPassword()));
        int update = mapper.updatePassByPhone(forGotPassDTO);
        if (update != 1) {
            String message = "修改密码失败，请稍后重试！";
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public JsonPage<UserListVO> isReturnPeopleList(Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        List<UserListVO> returnPeopleList = mapper.isReturnPeopleList();
        if (returnPeopleList.isEmpty()) {
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, "暂无返乡人员！");
        }
        return JsonPage.restPage(new PageInfo<>(returnPeopleList));
    }

    @Override
    public JsonPage<UserListVO> NotReturnPeopleList(Integer page, Integer pageSize) {
        PageHelper.startPage(page, pageSize);
        List<UserListVO> notReturnPeopleList = mapper.NotReturnPeopleList();
        if (notReturnPeopleList.isEmpty()) {
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, "暂无非返乡人员！");
        }
        return JsonPage.restPage(new PageInfo<>(notReturnPeopleList));
    }

    @Override
    public JsonPage<UserListVO> ListByUsernameOrName(Integer page, Integer pageSize, String usernameOrName) {
        PageHelper.startPage(page, pageSize);
        List<UserListVO> userListVOS = mapper.ListByUsernameOrName(usernameOrName);
        if (userListVOS.isEmpty()) {
            throw new ServiceException(ServiceCode.ERR_NOTFOUND, "用户名或姓名不存在，请重新输入！");
        }
        return JsonPage.restPage(new PageInfo<>(userListVOS));
    }
}
